#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <arpa/inet.h>

#include <event.h>

#include <unistd.h>

#ifdef __cplusplus
extern "C" {
#endif

#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

#ifdef __cplusplus
}
#endif

#include <time.h>
#include "log.h"

#include "lua_function.h"
#include "lua_network_function.h"
#include "lua_tc_function.h"

//struct event_base * main_base = 0;
lua_State * main_L = 0;

#define LUA_CALL(L, IN, OUT) lua_call(L, IN, OUT)

static void on_signal(evutil_socket_t fd, short event, void * p)
{
	struct event_base * base = (struct event_base*)base;	
	lua_getglobal(main_L, "on_signal");
	if (lua_isfunction(main_L, -1)) {
		lua_pushinteger(main_L, fd); 
		LUA_CALL(main_L, 1, 0);
	} else {
		lua_pop(main_L,1);
	}
	event_base_loopbreak(base);

}

static void on_timer(evutil_socket_t fd, short events, void * ctx)
{
	lua_getglobal(main_L, "on_timer");
	if (lua_isfunction(main_L, -1)) {
		LUA_CALL(main_L, 0, 0);
	} else {
		lua_pop(main_L,1);
	}
}

void Usage(char * prog) {
	printf("Usage: %s script ...\n", prog);
	printf("    function\n");
	printf("    |-- network\n");
	printf("    |   |-- listen(host, port)\n");
	printf("    |   |-- connect(host, port)\n");
	printf("    |   |-- write(conn, data)\n");
	printf("    |   `-- close(conn)\n");
	printf("    |-- tc\n");
	printf("    |   |-- open(file)\n");
	printf("    |   |-- close(db)\n");
	printf("    |   |-- put(db, key, val)\n");
	printf("    |   |-- get(db, key)\n");
	printf("    |   `-- out(db, key)\n");
	printf("    |-- bin\n");
	printf("    |   |-- from_int(val)\n");
	printf("    |   `-- to_int(val)\n");
	printf("    `-- loop\n");
	printf("        `-- exit()\n");
	printf("    call back\n");
	printf("    |-- on_accept(conn)\n");
	printf("    |-- on_closed(conn)\n");
	printf("    |-- on_connected(conn)\n");
	printf("    |-- on_error(conn)\n");
	printf("    |-- on_signal(signal)\n");
	printf("    |-- on_timer()\n");
	printf("    `-- process_message(conn, data)\n");
	exit(0);
}

int main(int argc, char * argv[])
{
	struct event_base * base = event_base_new();

	struct event * ev = evsignal_new(base, SIGINT, on_signal, base);
	evsignal_add(ev, NULL);

	int i;
	if (argc == 1) {
		Usage(argv[0]);
	}

	for(i = 1; i < argc; i++) {
		if (strcmp(argv[i], "-h") == 0) {
			Usage(argv[0]);
		}
	}

	lua_State * L = luaL_newstate();
	main_L = L;
	luaL_openlibs(L);
	registe_base_function(L, base);
	registe_network_function(L, base);
	registe_tc_function(L);

	for(i = 1; i < argc; i++) {
		if(luaL_loadfile(L, argv[i])) {
			WRITE_ERROR_LOG("load %s failed\n", argv[i]);
			return -1;
		}
		lua_call(L, 0, 0);
	}

	if (script_exit) {
		return 0;
	}

/*
	lua_getglobal(main_L, "process_message");
	if (!lua_isfunction(main_L, -1)) {
		printf("process_respond isn't function\n");
		return -1;
	}
	lua_pop(main_L,1);

	lua_getglobal(main_L, "on_connected");
	if (!lua_isfunction(main_L, -1)) {
		printf("on_connected isn't function\n");
		return -1;
	}
	lua_pop(main_L,1);
*/
	lua_getglobal(main_L, "on_timer");
	if (lua_isfunction(main_L, -1)) {
		struct event * ev = event_new(base, -1, EV_PERSIST, on_timer, 0);
		struct timeval tv;
		tv.tv_sec = 1;
		tv.tv_usec = 0;
		evtimer_add(ev, &tv);
	}
	lua_pop(main_L,1);

	event_base_dispatch(base);
	event_base_free(base);
	return 0;
}
